"use strict";

var $ = require("jquery"),
    translator = require("../../animation/translator"),
    Widget = require("../widget/ui.widget"),
    eventUtils = require("../../events/utils"),
    commonUtils = require("../../core/utils/common"),
    pointerEvents = require("../../events/pointer");

var SCROLLBAR = "dxScrollbar",
    SCROLLABLE_SCROLLBAR_CLASS = "dx-scrollable-scrollbar",
    SCROLLABLE_SCROLLBAR_ACTIVE_CLASS = SCROLLABLE_SCROLLBAR_CLASS + "-active",
    SCROLLABLE_SCROLL_CLASS = "dx-scrollable-scroll",
    SCROLLABLE_SCROLL_CONTENT_CLASS = "dx-scrollable-scroll-content",
    HOVER_ENABLED_STATE = "dx-scrollbar-hoverable",
    HORIZONTAL = "horizontal",
    THUMB_MIN_SIZE = 15;

var SCROLLBAR_VISIBLE = {
    onScroll: "onScroll",
    onHover: "onHover",
    always: "always",
    never: "never"
};

var Scrollbar = Widget.inherit({
    _getDefaultOptions: function() {
        return $.extend(this.callBase(), {
            direction: null,
            visible: false,
            activeStateEnabled: false,
            visibilityMode: SCROLLBAR_VISIBLE.onScroll,
            containerSize: 0,
            contentSize: 0,
            expandable: true
        });
    },

    _init: function() {
        this.callBase();
        this._isHovered = false;
    },

    _render: function() {
        this._renderThumb();
        this.callBase();

        this._renderDirection();
        this._update();
        this._attachPointerDownHandler();
        this.option("hoverStateEnabled", this._isHoverMode());

        this.element().toggleClass(HOVER_ENABLED_STATE, this.option("hoverStateEnabled"));
    },

    _renderThumb: function() {
        this._$thumb = $("<div>").addClass(SCROLLABLE_SCROLL_CLASS);
        $("<div>").addClass(SCROLLABLE_SCROLL_CONTENT_CLASS).appendTo(this._$thumb);

        this.element().addClass(SCROLLABLE_SCROLLBAR_CLASS).append(this._$thumb);
    },

    isThumb: function($element) {
        return !!this.element().find($element).length;
    },

    _isHoverMode: function() {
        var visibilityMode = this.option("visibilityMode");
        return (visibilityMode === SCROLLBAR_VISIBLE.onHover || visibilityMode === SCROLLBAR_VISIBLE.always) && this.option("expandable");
    },

    _renderDirection: function() {
        var direction = this.option("direction");
        this.element().addClass("dx-scrollbar-" + direction);
        this._dimension = direction === HORIZONTAL ? "width" : "height";
        this._prop = direction === HORIZONTAL ? "left" : "top";
    },

    _attachPointerDownHandler: function() {
        this._$thumb.on(eventUtils.addNamespace(pointerEvents.down, SCROLLBAR), $.proxy(this.feedbackOn, this));
    },

    feedbackOn: function() {
        this.element().addClass(SCROLLABLE_SCROLLBAR_ACTIVE_CLASS);
        activeScrollbar = this;
    },

    feedbackOff: function() {
        this.element().removeClass(SCROLLABLE_SCROLLBAR_ACTIVE_CLASS);
        activeScrollbar = null;
    },

    cursorEnter: function() {
        this._isHovered = true;
        this.option("visible", true);
    },

    cursorLeave: function() {
        this._isHovered = false;
        this.option("visible", false);
    },

    _renderDimensions: function() {
        this._$thumb.css({
            width: this.option("width"),
            height: this.option("height")
        });
    },

    _toggleVisibility: function(visible) {
        if(this.option("visibilityMode") === SCROLLBAR_VISIBLE.onScroll) {
            // NOTE: need to relayout thumb and show it instantly
            this._$thumb.css("opacity");
        }

        visible = this._adjustVisibility(visible);

        this.option().visible = visible;
        this._$thumb.toggleClass("dx-state-invisible", !visible);
    },

    _adjustVisibility: function(visible) {
        if(this.containerToContentRatio() && !this._needScrollbar()) {
            return false;
        }

        switch(this.option("visibilityMode")) {
            case SCROLLBAR_VISIBLE.onScroll:
                break;
            case SCROLLBAR_VISIBLE.onHover:
                visible = visible || !!this._isHovered;
                break;
            case SCROLLBAR_VISIBLE.never:
                visible = false;
                break;
            case SCROLLBAR_VISIBLE.always:
                visible = true;
                break;
        }

        return visible;
    },

    moveTo: function(location) {
        if(this._isHidden()) {
            return;
        }

        if($.isPlainObject(location)) {
            location = location[this._prop] || 0;
        }

        var scrollBarLocation = {};
        scrollBarLocation[this._prop] = this._calculateScrollBarPosition(location);
        translator.move(this._$thumb, scrollBarLocation);
    },

    _calculateScrollBarPosition: function(location) {
        return -location * this._thumbRatio;
    },

    _update: function() {
        var containerSize = Math.round(this.option("containerSize")),
            contentSize = Math.round(this.option("contentSize"));

        this._containerToContentRatio = (contentSize ? containerSize / contentSize : containerSize);
        var thumbSize = Math.round(Math.max(Math.round(containerSize * this._containerToContentRatio), THUMB_MIN_SIZE));
        this._thumbRatio = (containerSize - thumbSize) / (contentSize - containerSize);

        this.option(this._dimension, thumbSize);
        this.element().css("display", this._needScrollbar() ? "" : "none");
    },

    _isHidden: function() {
        return this.option("visibilityMode") === SCROLLBAR_VISIBLE.never;
    },

    _needScrollbar: function() {
        return !this._isHidden() && (this._containerToContentRatio < 1);
    },

    containerToContentRatio: function() {
        return this._containerToContentRatio;
    },

    _normalizeSize: function(size) {
        return $.isPlainObject(size) ? size[this._dimension] || 0 : size;
    },

    _clean: function() {
        this.callBase();
        if(this === activeScrollbar) {
            activeScrollbar = null;
        }

        this._$thumb.off("." + SCROLLBAR);
    },

    _optionChanged: function(args) {
        if(this._isHidden()) {
            return;
        }

        switch(args.name) {
            case "containerSize":
            case "contentSize":
                this.option()[args.name] = this._normalizeSize(args.value);
                this._update();
                break;
            case "visibilityMode":
            case "direction":
                this._invalidate();
                break;
            default:
                this.callBase.apply(this, arguments);
        }
    },

    update: commonUtils.deferRenderer(function() {
        this._adjustVisibility() && this.option("visible", true);
    })
});

var activeScrollbar = null;

$(document).on(eventUtils.addNamespace(pointerEvents.up, SCROLLBAR), function() {
    if(activeScrollbar) {
        activeScrollbar.feedbackOff();
    }
});

module.exports = Scrollbar;
